Estoy creando un enrutador con ExpressJs (usando TypeScript) y mi controlador de errores personalizado no detecta las excepciones, aquí está el código:
En el archivo index.ts (que es el principal):
import express, { Express } from 'express'; import cors from 'cors'; import { config } from '~/utils/config'; import { NotFoundRoute } from '~/middlewares/NotFound'; import { ExceptionHandler } from '~/middlewares/ExceptionHandler'; import { usersRouter } from '~/controllers/users'; const app: Express = express(); app.use(express.json()); app.use(cors()); app.use('/users', usersRouter); app.all('*', NotFoundRoute); app.use(ExceptionHandler); app.listen(config.port, () => console.log("API is running on port " + config.port));El controlador de excepciones personalizado:
import { NextFunction, Request, Response } from 'express'; export const ExceptionHandler = (err: any, req: Request, res: Response, next: NextFunction) => { if (res.headersSent) return next(err); if (err.status && err.message) { res.status(err.status).send({ error: err.message }); } else return res.status(500).send({ message: "Internal Server Error" }); } El enrutador que es problemático (donde InternalServerError no es detectado por lo anterior):
import { Request, Response, Router } from 'express'; import { User } from '~/schemas/User'; import { InternalServerError } from '~/errors/InternalServerError'; const usersRouter = Router(); usersRouter.get('/', async (req: Request, res: Response) => { try { const users = await User.find({}); res.status(200).send(users); } catch (err) { res.status(500).send({ message: "Failed to fetch users"}); } }) usersRouter.post('/register', async (req: Request, res: Response) => { try { const { email, password } = req.body; if (!email || !password) res.status(403).send({ message: "Bad Request"}); const newUser = User.createUser({ email, password }); await newUser.save(); res.status(201).send(newUser); } catch (err) { throw new InternalServerError(); } }) export { usersRouter }; Todas mis excepciones no se detectan, lo que significa que no están relacionadas con excepciones. En el archivo index.ts , NotFoundRoute arroja una excepción que se detecta, así que supongo que funciona en el contexto del archivo. ¿Cómo no está funcionando? Supongo que el enrutador tiene una excepción lanzada que se detectaría, pero no lo es.
Para recordar el contexto, estoy tratando de forzar que ocurran errores para ver si el manejo de errores es correcto. Así que en este caso obligué
newUser.save()fallar
Express no puede manejar excepciones thrown o promesas rejected . Para indicarle a express que hay un error, debe llamar a la función next() en lugar de usar throw o rechazar una Promesa:
usersRouter.post('/register', async (req: Request, res: Response, next: Function) => { try { const { email, password } = req.body; if (!email || !password) res.status(403).send({ message: "Bad Request"}); const newUser = User.createUser({ email, password }); await newUser.save(); res.status(201).send(newUser); } catch (err) { next(new InternalServerError()); // This is how you "throw" errors // in Express } }) Tenga en cuenta que express solo espera que llame a la función que pasa como el tercer argumento. El nombre del argumento depende de usted. Puedes usar otras palabras además de next :
usersRouter.post('/register', async (req: Request, res: Response, error: Function) => { try { /* some logic */ } catch (err) { error(new InternalServerError()); } }) Aunque tradicionalmente el nombre del tercer argumento es el next y la mayoría de los desarrolladores de JavaScript esperan que sea ese.
Agregando a la respuesta de slebetman: puede generar errores que serán manejados por el controlador de excepciones, pero solo en el middleware síncrono . Puedes probarlo:
app.use("/sync", function(req, res) { throw "sync"; }) .use("/async", async function(req, res) { throw "async"; }) .use(function(err, req, res, next) { res.end("Caught " + err); });